package simple_log

import (
	"fmt"
	"log"
	"os"
	"sync"
	"time"
	"io"
)

const (
	InfoLevel = iota
	WarnLevel
	ErrorLevel
)

var logLevelTag = []string{
	"Info",
	"Warn",
	"Error",
}

type Logger struct {
	dir string
	l *log.Logger
	unix int64
}

var loggerLock = &sync.RWMutex{}
var loggers = make(map[string]*Logger)

func newLogFile(dir string) (write io.Writer, err error) {
	today := time.Now().Format("2006-01-02")
	logFilePath := dir + "/" + today + ".log"
	logFile, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)
	if err != nil {
		return
	}
	write = logFile
	return
}

func NewLogger(key string, dir string) *Logger {
	logFile, err := newLogFile(dir)
	if err != nil {
		panic(err.Error())
	}
	rtn := &Logger{
		dir: dir,
		l: log.New(logFile, "", log.LstdFlags),
		unix: time.Now().Unix(),
	}
	go rtn.splitLogFile()
	loggerLock.Lock()
	loggers[key] = rtn
	loggerLock.Unlock()
	return rtn
}

func GetLogger(key string) *Logger {
	loggerLock.RLock()
	defer loggerLock.RUnlock()
	l := loggers[key]
	return l
}

func (l *Logger) Info(format string, v ...any) {
	l.write(InfoLevel, format, v...)
}

func (l *Logger) Warn(format string, v ...any) {
	l.write(WarnLevel, format, v...)
}

func (l *Logger) Err(format string, v ...any) {
	l.write(ErrorLevel, format, v...)
	panic("Fatal Error")
}

func (l *Logger) write(level int, format string, v ...any) {
	category := logLevelTag[level]
	nanoSecond := time.Now().Nanosecond()
	l.l.Println(fmt.Sprintf("%d %s : %s", nanoSecond, category, fmt.Sprintf(format, v...)))
}

func (l *Logger) splitLogFile() {
	for {
		time.Sleep(time.Duration(getTimeDifference()) * time.Second)
		newLog, err := newLogFile(l.dir)
		if err != nil {
			l.Warn("splitLogFile newLogFile err:%s", err.Error())
			continue
		}
		l.l = log.New(newLog, "", log.LstdFlags)
	}
}

// getTimeDifference 获取当前时间 到 明天0点整的时间差的秒级时间戳
func getTimeDifference() int64 {
	nowTime := time.Now()
	// 当天秒级时间戳
	nowTimeStamp := nowTime.Unix()
	nowTimeStr := nowTime.Format("2006-01-02")
	//使用Parse 默认获取为UTC时区 需要获取本地时区 所以使用ParseInLocation
	t2, _ := time.ParseInLocation("2006-01-02", nowTimeStr, time.Local)
	// 第二天零点时间戳
	towTimeStamp := t2.AddDate(0, 0, 1).Unix()
	return towTimeStamp - nowTimeStamp
}